package com.duobaoyu.dby.supply.biz.service.order.event;

import cn.hutool.core.lang.Pair;
import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson.JSON;
import com.duobaoyu.dby.channel.adapter.enums.ChannelCodeEnum;
import com.duobaoyu.dby.channel.adapter.enums.biz.order.OrderTypeEnum;
import com.duobaoyu.dby.channel.adapter.util.ChannelCodeUtils;
import com.duobaoyu.dby.common.mybatis.util.EnumUtils;
import com.duobaoyu.dby.supply.biz.client.boundary.order.OrderBoundaryClient;
import com.duobaoyu.dby.supply.biz.client.boundary.order.bean.bo.OrderAddressBO;
import com.duobaoyu.dby.supply.biz.client.boundary.order.bean.bo.OrderBO;
import com.duobaoyu.dby.supply.biz.client.boundary.order.bean.bo.OrderProductBO;
import com.duobaoyu.dby.supply.biz.client.boundary.order.bean.bo.UpdateOrderBO;
import com.duobaoyu.dby.supply.biz.client.product.ProductCenterApiClient;
import com.duobaoyu.dby.supply.biz.constant.SupplyChainConstants;
import com.duobaoyu.dby.supply.biz.converter.OrderConverter;
import com.duobaoyu.dby.supply.biz.enums.OrderParentTypeEnum;
import com.duobaoyu.dby.supply.biz.producer.SupplyChainMQProducer;
import com.duobaoyu.dby.supply.biz.service.order.OrderService;
import com.duobaoyu.dby.supply.biz.util.IdGeneratorUtil;
import com.duobaoyu.dby.supply.common.biz.bo.order.ChannelOrderDetailInBO;
import com.duobaoyu.dby.supply.common.biz.bo.order.ChannelOrderDetailOutBO;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 订单确认成功事件监听
 *
 * @author chenms
 * @date 2023/11/16 10:53 AM
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class OrderConfirmSuccessEventListener implements ApplicationListener<OrderConfirmSuccessEvent> {

    private final OrderConverter orderConverter;
    private final OrderBoundaryClient orderBoundaryClient;
    private final OrderService orderService;
    private final ProductCenterApiClient productCenterApiClient;
    private final SupplyChainMQProducer supplyChainMQProducer;

    @Override
    @Async(value = SupplyChainConstants.THREAD_POOL_NAME)
    public void onApplicationEvent(OrderConfirmSuccessEvent event) {
        log.info("收到确认成功事件");
        if (log.isDebugEnabled()) {
            log.debug("收到确认成功事件详细参数:{}", JSON.toJSONString(event));
        }
        OrderBO order = event.getOrder();
        // 行运和天猫渠道要在确认回调后才有必要参数, 不支持确认订单后立即查询
        if (EnumUtils.eq(ChannelCodeEnum.XING_YUN, order.getChannelCode()) || EnumUtils.eq(ChannelCodeEnum.LINKED_MALL, order.getChannelCode())) {
            return;
        }
        ChannelOrderDetailOutBO channelOrderInfo = this.getChannelOrderInfo(order);
        // 更新渠道订单实际运费
        if (Objects.nonNull(channelOrderInfo.getChannelFreightAmount())) {
            this.updateChannelActualFreight(order, channelOrderInfo.getChannelFreightAmount());
        }
        // 根据渠道订单信息对订单拆单
        if (ChannelCodeUtils.isNeedSplitOrderAfterConfirmSuccess(order.getChannelCode(), order.getOrderType())) {
            this.splitOrderFromChannelOrderInfo(order, channelOrderInfo);
        }
        // 检查商品价格
        if (ChannelCodeUtils.isVirtual(order.getChannelCode())) {
            this.checkProductPrice(order, channelOrderInfo);
        }
    }

    /**
     * 更新渠道真实运费
     */
    private void updateChannelActualFreight(OrderBO order, BigDecimal channelActualFreightAmount) {
        try {
            if (Objects.nonNull(order) && Objects.nonNull(channelActualFreightAmount)) {
                order.setChannelOrderRealityAmount(channelActualFreightAmount);
                UpdateOrderBO updateOrder = UpdateOrderBO.builder().orderSn(order.getOrderSn()).channelActualFreightAmount(channelActualFreightAmount).build();
                orderService.updateOrderByOrderSn(updateOrder);
            }
        } catch (Exception e) {
            log.warn("更新渠道实际运费异常", e);
        }
    }

    /**
     * 检查订单商品价格,存在变动则下架
     *
     * @param order            拆单前的原始单
     * @param channelOrderInfo 渠道订单明细
     */
    private void checkProductPrice(OrderBO order, ChannelOrderDetailOutBO channelOrderInfo) {
        try {
            // 检查虚拟订单, 如果订单价格发生变动对订单商品进行下架
            if (EnumUtils.neq(OrderTypeEnum.REAL_ORDER, order.getOrderType())) {
                if (Objects.nonNull(channelOrderInfo.getChannelOrderAmount()) && order.getChannelOrderAmount().compareTo(channelOrderInfo.getChannelOrderAmount()) < 0) {
                    log.info("虚拟订单渠道总价不一致,对订单商品进行下架: orderBO={}, channelOrderInfo={}", JSON.toJSONString(order), JSON.toJSONString(channelOrderInfo));
                    List<String> skuCodeList = order.getOrderProductList().stream().map(OrderProductBO::getSkuCode).distinct().collect(Collectors.toList());
                    productCenterApiClient.offShelfProducts(skuCodeList);
                }
            }
        } catch (Exception e) {
            log.warn("检查订单价格异常", e);
        }
    }

    private ChannelOrderDetailOutBO getChannelOrderInfo(OrderBO order) {
        Set<String> productTypeSet = order.getOrderProductList().stream().map(OrderProductBO::getProductType).collect(Collectors.toSet());
        ChannelOrderDetailInBO channelOrderDetailIn = ChannelOrderDetailInBO.builder()
                .channelOrderSn(order.getChannelOrderSn())
                .channelCode(order.getChannelCode())
                .orderSn(order.getOrderSn())
                .orderTradeSn(order.getOrderTradeSn())
                .channelOrderParentSn(order.getChannelOrderParentSn())
                .channelTradeOrderSn(order.getChannelTradeOrderSn())
                .originalPrice(Optional.ofNullable(order.getOrderProductList()).map(
                        productList -> productList.stream().findFirst().map(OrderProductBO::getOriginalPrice).orElse(null)
                ).orElse(null))
                .orderProductTypeSet(productTypeSet).build();
        return orderBoundaryClient.getChannelOrderDetail(channelOrderDetailIn);
    }

    /**
     * 根据渠道订单明细拆单
     */
    private void splitOrderFromChannelOrderInfo(OrderBO order, ChannelOrderDetailOutBO channelOrderInfo) {
        try {
            List<ChannelOrderDetailOutBO.RealOrderDetail> realOrderDetailList = channelOrderInfo.getRealOrderDetailList();
            // 实物拆单
            Pair<OrderBO, List<OrderBO>> orderListPair = this.realOrderSplit(order, channelOrderInfo, realOrderDetailList);
            Optional.ofNullable(orderListPair).ifPresent(item -> {
                orderService.saveSpiltOrder(item);
                supplyChainMQProducer.orderAlterSend(order.getSupplyTradeSn(), order.getServerName());
            });
            // 虚拟订单拆单
            List<ChannelOrderDetailOutBO.VirtualOrderDetail> virtualOrderDetailList = channelOrderInfo.getVirtualOrderDetailList();
            Pair<OrderBO, List<OrderBO>> virtualOrderSplitResult = this.virtualOrderSplit(order, channelOrderInfo, virtualOrderDetailList);
            Optional.ofNullable(virtualOrderSplitResult).ifPresent(item -> {
                orderService.saveSpiltOrder(item);
                supplyChainMQProducer.orderAlterSend(order.getSupplyTradeSn(), order.getServerName());
            });
        } catch (Exception e) {
            log.warn("根据渠道订单明细拆单异常 orderSn={}", Optional.ofNullable(order).map(OrderBO::getOrderSn).orElse(null), e);
        }
    }

    /**
     * 虚拟订单拆单
     */
    private Pair<OrderBO, List<OrderBO>> virtualOrderSplit(OrderBO order, ChannelOrderDetailOutBO channelOrderInfo, List<ChannelOrderDetailOutBO.VirtualOrderDetail> virtualOrderDetailList) {
        if (CollectionUtils.isNotEmpty(virtualOrderDetailList)) {
            log.info("根据渠道订单信息对虚拟订单进行拆单");
            if (log.isDebugEnabled()) {
                log.debug("根据渠道订单信息对虚拟订单进行拆单明细: [orderBO={}, channelOrderInfo = {}]", JSON.toJSONString(order), JSON.toJSONString(channelOrderInfo));
            }
            List<OrderBO> newOrderList = Lists.newArrayList();
            for (ChannelOrderDetailOutBO.VirtualOrderDetail virtualOrderDetail : virtualOrderDetailList) {
                // 拆单后的商品不一定包含所有商品, 不拷贝订单商品
                List<OrderProductBO> orderProductList = order.getOrderProductList();
                order.setOrderProductList(null);
                OrderBO newOrder = orderConverter.copy(order);
                order.setOrderProductList(orderProductList);
                String newOrderSn = IdGeneratorUtil.getOrderSn(ChannelCodeEnum.getChannelCodeEnumByCode(newOrder.getChannelCode()).getCode(), newOrder.getServerName());
                newOrder.setOrderSn(newOrderSn);
                newOrder.setChannelOrderSn(virtualOrderDetail.getChannelOrderSn());
                newOrder.setParentType(OrderParentTypeEnum.AFTER_SPLIT.getValue());
                newOrder.setChannelFreightAmount(BigDecimal.ZERO);
                newOrder.setOrderParentSn(order.getOrderSn());
                Integer channelOrderStatus = Optional.ofNullable(virtualOrderDetail.getStatus()).orElse(channelOrderInfo.getStatus());
                newOrder.setOrderStatus(Optional.ofNullable(channelOrderStatus).orElse(order.getOrderStatus()));

                BigDecimal newOrderAmount = BigDecimal.ZERO;
                BigDecimal newChannelOrderRealityAmount = BigDecimal.ZERO;
                BigDecimal newChannelAmount = BigDecimal.ZERO;

                // 订单商品
                List<OrderProductBO> newOrderProducts = orderProductList.stream().filter(item -> Objects.equals(item.getChannelSkuCode(), virtualOrderDetail.getChannelSkuCode()))
                        .map(item -> orderConverter.copyOrderProduct(item)).collect(Collectors.toList());
                for (OrderProductBO newOrderProduct : newOrderProducts) {

                    newOrderProduct.setOrderSn(newOrderSn);
                    Integer skuNum = virtualOrderDetail.getNum();
                    newOrderProduct.setSkuNum(skuNum);
                    // 平台成本总额
                    BigDecimal platformAmount = newOrderProduct.getPlatformPrice().multiply(BigDecimal.valueOf(skuNum));
                    newOrderProduct.setChannelPayAmount(Optional.ofNullable(virtualOrderDetail.getChannelOrderAmount()).orElse(platformAmount));
                    newOrderProduct.setPlatformAmount(platformAmount);
                    newOrderProduct.setPlatformSellAmount(newOrderProduct.getPlatformSellPrice().multiply(BigDecimal.valueOf(skuNum)));
                    // 保存卡密信息
                    if (CollectionUtils.isNotEmpty(virtualOrderDetail.getCardList())) {
                        OrderProductBO.OrderProductResultExtendInfo orderProductResultExtendInfo = new OrderProductBO.OrderProductResultExtendInfo();
                        orderProductResultExtendInfo.setCouponInfos(orderConverter.toOrderProductCouponExtendInfoList(virtualOrderDetail.getCardList()));
                        newOrderProduct.setResultExtend(orderProductResultExtendInfo);
                    }
                    // 累计订单总额
                    newChannelAmount = newChannelAmount.add(platformAmount);
                    newChannelOrderRealityAmount = newChannelOrderRealityAmount.add(newOrderProduct.getChannelPayAmount());
                    newOrderAmount = newOrderAmount.add(newOrderProduct.getPlatformSellAmount());
                }
                newOrder.setChannelOrderAmount(newChannelAmount);
                newOrder.setChannelOrderRealityAmount(newChannelOrderRealityAmount);
                newOrder.setOrderAmount(newOrderAmount);
                newOrder.setOrderProductList(newOrderProducts);
                newOrderList.add(newOrder);
            }
            Pair<OrderBO, List<OrderBO>> splitResult = Pair.of(order, newOrderList);
            if (log.isDebugEnabled()) {
                log.debug("拆单结果:{}", JSON.toJSONString(splitResult));
            }
            return splitResult;
        }
        return null;
    }

    /**
     * 实物订单拆单
     *
     * @param order
     * @param channelOrderInfo
     * @param realOrderDetailList
     * @return
     */
    private Pair<OrderBO, List<OrderBO>> realOrderSplit(OrderBO order, ChannelOrderDetailOutBO channelOrderInfo, List<ChannelOrderDetailOutBO.RealOrderDetail> realOrderDetailList) {
        if (CollectionUtils.isNotEmpty(realOrderDetailList)) {
            log.info("根据渠道订单信息对实物订单进行拆单");
            if (log.isDebugEnabled()) {
                log.debug("根据渠道订单信息对实物订单进行拆单明细: [orderBO={}, channelOrderInfo = {}]", JSON.toJSONString(order), JSON.toJSONString(channelOrderInfo));
            }
            List<OrderBO> newOrderList = new ArrayList<>();
            List<OrderProductBO> orderProductList = order.getOrderProductList();
            for (ChannelOrderDetailOutBO.RealOrderDetail realOrderDetail : realOrderDetailList) {
                // 拆单后的商品不一定包含所有商品, 不拷贝订单商品
                order.setOrderProductList(null);
                OrderBO newOrder = orderConverter.copy(order);
                order.setOrderProductList(orderProductList);
                String newOrderSn = IdGeneratorUtil.getOrderSn(ChannelCodeEnum.getChannelCodeEnumByCode(newOrder.getChannelCode()).getCode(), newOrder.getServerName());
                newOrder.setOrderSn(newOrderSn);
                newOrder.setChannelOrderSn(realOrderDetail.getChannelOrderSn());
                newOrder.setParentType(OrderParentTypeEnum.AFTER_SPLIT.getValue());
                newOrder.setChannelFreightAmount(realOrderDetail.getChannelFreightAmount());
                newOrder.setOrderParentSn(order.getOrderSn());
                newOrder.setChannelActualFreightAmount(Optional.ofNullable(realOrderDetail.getChannelFreightAmount()).orElse(BigDecimal.ZERO));
                newOrder.setChannelFreightAmount(Optional.ofNullable(realOrderDetail.getChannelFreightAmount()).orElse(BigDecimal.ZERO));
                Integer channelOrderStatus = Optional.ofNullable(realOrderDetail.getStatus()).orElse(channelOrderInfo.getStatus());
                newOrder.setOrderStatus(Optional.ofNullable(channelOrderStatus).orElse(order.getOrderStatus()));
                List<ChannelOrderDetailOutBO.RealOrderDetail.RealOrderSkuInfo> skuInfos = realOrderDetail.getSkuInfos();
                List<OrderProductBO> newOrderProductList = new ArrayList<>(skuInfos.size());
                BigDecimal newOrderAmount = BigDecimal.ZERO;
                BigDecimal newChannelOrderRealityAmount = BigDecimal.ZERO;
                BigDecimal newChannelAmount = BigDecimal.ZERO;
                for (ChannelOrderDetailOutBO.RealOrderDetail.RealOrderSkuInfo skuInfo : skuInfos) {
                    for (OrderProductBO orderProduct : orderProductList) {
                        if (Objects.equals(skuInfo.getChannelSkuCode(), orderProduct.getChannelSkuCode())) {
                            OrderProductBO newOrderProduct = orderConverter.copyOrderProduct(orderProduct);
                            Integer skuNum = skuInfo.getSkuNum();
                            newOrderProduct.setSkuNum(skuNum);
                            // 渠道商品真实单价
                            BigDecimal channelSkuRealUnitPrice = Optional.ofNullable(skuInfo.getChannelSkuUnitPrice()).orElse(orderProduct.getPlatformPrice());
                            newOrderProduct.setChannelPayAmount(Optional.ofNullable(skuInfo.getPaymentAmount())
                                    .orElse(NumberUtil.mul(channelSkuRealUnitPrice, new BigDecimal(skuNum))));
                            newOrderProduct.setPlatformSellAmount(orderProduct.getPlatformSellPrice().multiply(BigDecimal.valueOf(skuNum)));
                            newOrderProduct.setPlatformAmount(orderProduct.getPlatformPrice().multiply(BigDecimal.valueOf(skuNum)));
                            newOrderProduct.setChannelReturnFreightAmount(skuInfo.getChannelReturnFreightAmount());
                            newOrderProduct.setChannelReturnSkuNum(skuInfo.getChannelReturnSkuNum());
                            newOrderProduct.setOrderSn(newOrderSn);
                            newOrderProductList.add(newOrderProduct);
                            // 累计订单总额
                            newChannelAmount = newChannelAmount.add(newOrderProduct.getPlatformAmount());
                            newChannelOrderRealityAmount = newChannelOrderRealityAmount.add(newOrderProduct.getChannelPayAmount());
                            newOrderAmount = newOrderAmount.add(newOrderProduct.getPlatformSellAmount());
                        }
                    }
                }
                newOrder.setOrderAmount(newOrderAmount);
                newOrder.setChannelOrderRealityAmount(newChannelOrderRealityAmount);
                newOrder.setChannelOrderAmount(newChannelAmount);
                newOrder.setOrderProductList(newOrderProductList);
                // 重新生成订单地址
                OrderAddressBO newOrderAddress = orderConverter.copyOrderAddress(newOrder.getOrderAddress());
                Optional.ofNullable(newOrderAddress).ifPresent(address -> address.setOrderSn(newOrderSn));
                newOrder.setOrderAddress(newOrderAddress);
                newOrderList.add(newOrder);
            }
            Pair<OrderBO, List<OrderBO>> splitResult = Pair.of(order, newOrderList);
            if (log.isDebugEnabled()) {
                log.debug("拆单结果:{}", JSON.toJSONString(splitResult));
            }
            return splitResult;
        }
        return null;
    }

}
